﻿#region << 文件说明 >>

/*----------------------------------------------------------------
 * 命名空间：Vampirewal.Core.SocketCore.Models
 * 唯一标识：ad1c07ba-2b29-4a97-8343-b6515109252e
 * 文件名：DynamicModelBase
 *
 * 创建者：杨程
 * 电子邮箱：235160615@qq.com
 * 创建时间：2025/5/21 15:02:49
 * 版本：V1.0.0
 * 描述：
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/

#endregion << 文件说明 >>

namespace Vampirewal.Core.Models;


/*
 * 如何使用:
 *  public partial class TestDynamic : DynamicModelBase
    {
        public TestDynamic()
        {
            // 初始化动态属性
            this["DynamicProperty"] = "Initial Value";
        }
    }

    在xaml上正常绑定就行
    <TextBlock Foreground="{StaticResource BaseForeground}" Text="{Binding Test.DynamicProperty, Mode=TwoWay}" />

    通过这种方式添加的属性，不会被json序列化
 */


public class DynamicModelBase : ObservableObject, ICustomTypeDescriptor
{
    private readonly ConcurrentDictionary<string, object?> properties = new ConcurrentDictionary<string, object?>();


    public object? this[string propertyName]
    {
        get => GetValue(propertyName);
        set => SetValue(propertyName, value);
    }



    public object? GetValue(string propertyName)
    {
        properties.TryGetValue(propertyName, out var value);
        return value;
    }

    public void SetValue(string propertyName, object? value)
    {
        if (properties.TryGetValue(propertyName, out object? oldValue))
        {
            if (!Equals(oldValue, value))
            {
                if (properties.TryUpdate(propertyName, value, oldValue))
                {
                    OnPropertyChanged(propertyName);
                }
            }
        }
        else
        {
            properties.TryAdd(propertyName, value);
            OnPropertyChanged(propertyName);
        }
    }




    public AttributeCollection GetAttributes() => TypeDescriptor.GetAttributes(this, false);
    public string GetClassName() => TypeDescriptor.GetClassName(this, false);
    public string GetComponentName() => TypeDescriptor.GetComponentName(this, false);
    public TypeConverter GetConverter() => TypeDescriptor.GetConverter(this, false);
    public EventDescriptor GetDefaultEvent() => TypeDescriptor.GetDefaultEvent(this, false);
    public PropertyDescriptor GetDefaultProperty() => null; // 动态属性无默认属性
    public object GetEditor(Type editorBaseType) => TypeDescriptor.GetEditor(this, editorBaseType, false);
    public EventDescriptorCollection GetEvents(Attribute[]? attributes) => TypeDescriptor.GetEvents(this, attributes, false);
    public EventDescriptorCollection GetEvents() => TypeDescriptor.GetEvents(this, false);

    // 关键方法：返回动态属性集合
    public PropertyDescriptorCollection GetProperties() => GetProperties(null);

    public PropertyDescriptorCollection GetProperties(Attribute[]? attributes)
    {
        var props = new List<DynamicPropertyDescriptor>();
        foreach (var key in properties.Keys)
        {
            props.Add(new DynamicPropertyDescriptor(key));
        }
        return new PropertyDescriptorCollection(props.ToArray());
    }

    public object? GetPropertyOwner(PropertyDescriptor? pd) => this;
}

internal class DynamicPropertyDescriptor : PropertyDescriptor
{
    private readonly string _name;

    public DynamicPropertyDescriptor(string name)
        : base(name, null)
    {
        _name = name;
    }

    public override bool CanResetValue(object component) => true;
    public override Type ComponentType => typeof(DynamicModelBase);
    public override object GetValue(object component)
    {
        if (component is DynamicModelBase item)
        {
            return item[_name] ?? DBNull.Value; // 返回动态属性值
        }
        return null;
    }

    public override bool IsReadOnly => false;
    public override Type PropertyType => typeof(object);

    public override void ResetValue(object component) => SetValue(component, null);
    public override void SetValue(object component, object? value)
    {
        if (component is DynamicModelBase item)
        {
            item[_name] = value; // 触发 DynamicItem.SetValue
            //item.OnPropertyChanged(_name); // 显式通知属性变更
        }
    }

    public override bool ShouldSerializeValue(object component) => true;
}